//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <core.h>
#include <_hal.h>
#include <_context.h>
#include <_schedule.h>
#include <mantle.h>
#include <init.h>

//
//  class Thread
//
#ifdef _neptune
#define THREAD0_STACK_SIZE  (PAGE_SIZE * 4)
#else
#define THREAD0_STACK_SIZE  PAGE_SIZE
#endif

#if defined(_GNUC)
DECL_SECTION(".thread0")    byte_t g_thread0Stack[THREAD0_STACK_SIZE];

#elif defined(_EVC)
// TODO(mips): The g_thread0Stack must be alignment of 2 page
byte_t g_thread0Original[THREAD0_STACK_SIZE * 4];
byte_t *g_thread0Stack;
#else
#error unknown compiler
#endif
#define g_thread0           (*(Thread *)((void *)g_thread0Stack))

PreemptionLock Thread::s_freeListLock;
DLinkNode Thread::s_freeListHead;
uint_t Thread::s_uNumberOfFreeThreads = 0;

INLINE Thread *AllocThread()
{
    return (Thread *)DzAllocKernelPages(THREAD_STACK_ORDER);
}

INLINE void FreeThread(Thread *pThread)
{
    assert(pThread);
    assert(&g_thread0 != pThread);

    pThread->Uninitialize();
    DzFreeKernelPages(pThread, THREAD_STACK_ORDER);
}

void *Thread::operator new(size_t s)
{
    s_freeListLock.Lock();

    s_freeListHead.AssertValid(s_uNumberOfFreeThreads);

    if (0 == s_uNumberOfFreeThreads) {
        assert(s_freeListHead.IsEmpty());
        s_freeListLock.Unlock();

        return AllocThread();
    }

    register Thread *pThread = (Thread *)s_freeListHead.First();
    pThread->Detach(&s_uNumberOfFreeThreads);

    s_freeListLock.Unlock();

    pThread->Uninitialize();
    return pThread;
}

void Thread::operator delete(void *pv)
{
    assert(pv);

    s_freeListLock.Lock();

#ifdef _DEBUG
    Thread *pThread;
    ForEachDLinkNode(Thread *, pThread, &s_freeListHead) {
        assert(pThread != (Thread *)pv);
    }
#endif // _DEBUG

    s_freeListHead.AssertValid(s_uNumberOfFreeThreads);

    s_freeListHead.InsertFirst((Thread *)pv, &s_uNumberOfFreeThreads);

    s_freeListLock.Unlock();
}

INLINE void Thread::ReclaimFreeThreads()
{
//    kprintf("{free threads: %d}", s_uNumberOfFreeThreads);

    s_freeListLock.Lock();
    while (KCONFIG_THREADCACHE_WATERMARK < s_uNumberOfFreeThreads) {
        register Thread *pThread = (Thread *)s_freeListHead.First();
        assert(pThread);
        pThread->Detach(&s_uNumberOfFreeThreads);
        s_freeListLock.Unlock();

        FreeThread(pThread);

        s_freeListLock.Lock();
    }
    s_freeListLock.Unlock();
}

INLINE void Thread::CommonInitialize()
{
    m_uState                = ThreadState_Running;
    m_uPoolThreadState      = ThreadState_Unstarted;

    m_uNestedSuspend        = 0;

    m_bPendingInterrupt     = FALSE;
    m_bInterrupted          = FALSE;

    m_pBindingTimer         = NULL;

    m_pWaitingSyncObject    = NULL;

    m_undoOperationListHead.Initialize();

    m_bFinishing            = FALSE;

    m_ownedSyncObjectListHead.Initialize();

    m_bNeedReschedule       = FALSE;

    m_hcontext.Initialize();

    m_inProcLink.Initialize();

    m_bHasUserEntry         = FALSE;
    m_fnKernelEntry         = NULL;
    m_uUserStackBase        = 0;


    m_exitCode              = E_THREAD_ABORTED;
    m_joinEvent.m_bManualReset  = TRUE;
    m_isDllProcDetachThd    = FALSE;

    *m_wszName              = 0;

#ifdef _DEBUG
    m_startTime.seconds       = 0;
    m_startTime.microseconds  = 0;
    m_finishTime.seconds      = 0;
    m_finishTime.microseconds = 0;
#endif // _DEBUG

    m_uUserProcessorTicks       = 0;
    m_uPrivilegedProcessorTicks = 0;

    memset(m_pvFields, 0, TF_MINIMUM_AVAILABLE * sizeof(void *));

    m_unusedReaderUndoOperationList.Initialize();
    for (uint_t i = 0; i < MAX_NUMBER_OF_RUOS; i++) {
        m_readerUndoOperations[i].m_pRWLock = NULL;
        m_unusedReaderUndoOperationList.InsertLast(&m_readerUndoOperations[i]);
    }

    m_pBuffer       = NULL;
    m_uBufferSize   = 0;
    m_pClientThread = NULL;

#ifdef _DEBUG
    m_uEndMarker = THREAD_END_MARKER;
#endif // _DEBUG
}

INLINE ECode Thread::CommonInitialize2(
    ScheduleClass *pScheduleClass, uint_t uSchedulePolicy)
{
    assert(pScheduleClass);

    CommonInitialize();

    m_pScheduleClass = pScheduleClass;
    m_uSchedulePolicy = uSchedulePolicy;

    m_pScheduleClass->InitializeThread(this);

    uint32_t uFlags = SaveFlagsAndCli();
    m_pEffectiveScheduleClass->EnterRunningList(
        this, RunningReason_Initialize);
    RestoreIF(uFlags);

    return NOERROR;
}

INLINE ECode Thread::Initialize(
    threadentry_t threadentry,
    threadroutine_t threadroutine, void *pvParameter,
    ScheduleClass *pScheduleClass, uint_t uSchedulePolicy)
{
    m_pOwner            = NULL;
    m_vaKernelStack     = (byte_t *)this + (PAGE_SIZE << THREAD_STACK_ORDER);
    assert(!((uint32_t)m_vaKernelStack &
        ((PAGE_SIZE << THREAD_STACK_ORDER) - 1)));
    m_vaKernelStackPtr  =
        InitSystemThreadStack(this, threadentry, threadroutine, pvParameter);

    return CommonInitialize2(pScheduleClass, uSchedulePolicy);
}

INLINE ECode Thread::Initialize(
    CProcess *pOwner, threadroutine_t threadroutine, void *pvParameter,
    ScheduleClass *pScheduleClass, uint_t uSchedulePolicy)
{
    m_pOwner            = pOwner;
    m_vaKernelStack     = (byte_t *)this + (PAGE_SIZE << THREAD_STACK_ORDER);
    assert(!((uint32_t)m_vaKernelStack &
        ((PAGE_SIZE << THREAD_STACK_ORDER) - 1)));
    m_vaKernelStackPtr  = InitThreadStack(this, threadroutine, pvParameter);

    return CommonInitialize2(pScheduleClass, uSchedulePolicy);
}

DECL_CODEINIT void Thread::Initialize0(virtaddr_t vaKernelStack)
{
    m_pOwner            = NULL;
    m_vaKernelStack     = vaKernelStack;
    m_vaKernelStackPtr  = InitThread0Stack(this);

    CommonInitialize();

    m_activeLock.Initialize();

    GetScheduleClass(ThreadPriorityRank_Idle, &m_pScheduleClass,
        &m_uSchedulePolicy);

    m_pScheduleClass->InitializeThread(this);

    m_pEffectiveScheduleClass->EnterRunningList(
        this, RunningReason_Initialize);
}

void Thread::SetUserEntry(virtaddr_t vaUserStack, virtaddr_t vaUserEntry)
{
    SetThreadUserEntry(this, vaUserStack, vaUserEntry);
    m_bHasUserEntry = TRUE;
}

//void Thread::BindTimer(DzTimer *pTimer)
//{
//    assert(pTimer);
//    m_pBindingTimer = pTimer;
//}

// IMPORTANT: when disable interrupt
void Thread::CancelBindingTimer()
{
    if (NULL != m_pBindingTimer) {
        m_pBindingTimer->Cancel();
        m_pBindingTimer = NULL;
    }
}

// IMPORTANT: when disable interrupt
void Thread::DetachFromSyncObject(SyncObject *pWaitingSyncObject)
{
    assert(pWaitingSyncObject);
    assert(this->m_pWaitingSyncObject == pWaitingSyncObject);

    Detach();
    m_pWaitingSyncObject = NULL;
}

void Thread::AddUndoOperation(UndoOperation *pUndoOperation)
{
    assert(pUndoOperation);

    m_lock.Lock();
    m_undoOperationListHead.InsertFirst(pUndoOperation);
    m_lock.Unlock();
}

void Thread::RemoveUndoOperation(UndoOperation *pUndoOperation)
{
    assert(pUndoOperation);

    m_lock.Lock();
    if (NULL != pUndoOperation->m_pNext) {
        pUndoOperation->Detach();
        pUndoOperation->m_pNext = NULL;
    }
    m_lock.Unlock();
}

bool_t Thread::CanAcquireReaderLock()
{
    m_lock.Lock();
    bool_t bResult = !m_unusedReaderUndoOperationList.IsEmpty();
    m_lock.Unlock();
    return bResult;
}

void Thread::AddReaderUndoOperation(RWLock *pRWLock)
{
    assert(pRWLock);
    assert(!m_unusedReaderUndoOperationList.IsEmpty());

    m_lock.Lock();
    register ReaderUndoOperation *pReaderUndoOperation =
            (ReaderUndoOperation *)m_unusedReaderUndoOperationList.First();
    pReaderUndoOperation->Detach();
    pReaderUndoOperation->Initialize(this, pRWLock);
    m_lock.Unlock();
}

ReaderUndoOperation *Thread::FindReaderUndoOperation(RWLock *pRWLock)
{
    assert(pRWLock);

    m_lock.Lock();
    for (uint_t i = 0; i < MAX_NUMBER_OF_RUOS; i++) {
        if (m_readerUndoOperations[i].m_pRWLock == pRWLock) {
            m_lock.Unlock();
            return &m_readerUndoOperations[i];
        }
    }
    m_lock.Unlock();

    return NULL;
}

void Thread::RemoveReaderUndoOperation(
    ReaderUndoOperation *pReaderUndoOperation)
{
    assert(pReaderUndoOperation);

    m_lock.Lock();

    pReaderUndoOperation->Detach();

    pReaderUndoOperation->m_pRWLock = NULL;
    m_unusedReaderUndoOperationList.InsertLast(pReaderUndoOperation);

    m_lock.Unlock();
}

void Thread::IsReaderLockHeld(const RWLock *pRWLock, Boolean *pIsHeld)
{
    assert(pRWLock);
    assert(pIsHeld);

    m_lock.Lock();

    for (uint_t i = 0; i < MAX_NUMBER_OF_RUOS; i++) {
        if (m_readerUndoOperations[i].m_pRWLock == pRWLock) {
            m_lock.Unlock();
            *pIsHeld = TRUE;
            return;
        }
    }

    m_lock.Unlock();
    *pIsHeld = FALSE;
}

void Thread::IsWriterLockHeld(const RWLock *pRWLock, Boolean *pIsHeld)
{
    assert(pRWLock);
    assert(pIsHeld);

    m_lock.Lock();

    const UndoOperation *pUndoOperation;
    ForEachDLinkNode(const UndoOperation *, pUndoOperation,
        &m_undoOperationListHead) {
        if (pUndoOperation == pRWLock) {
            m_lock.Unlock();
            *pIsHeld = true;
            return;
        }
    }

    m_lock.Unlock();
    *pIsHeld = false;
}

// IMPORTANT: when own a spinlock so preemption disabled
ECode Thread::ReadyToWakeUp()
{
    ECode ec;

    // TODO: Need it?
    m_lock.Lock();

    assert(IsSleeping());
    assert(NULL == m_pWaitingSyncObject);

    m_pEffectiveScheduleClass->OnThreadWakeUp(this);

    m_uState &= ~ThreadState_InterruptibleSleeping;

    if (IsRunning()) {
        uint32_t uFlags = SaveFlagsAndCli();
        m_pEffectiveScheduleClass->EnterRunningList(
            this, RunningReason_WakeUp);
        RestoreIF(uFlags);
        ec = NOERROR;
    }
    else {
        ec = S_FALSE;
    }

    m_lock.Unlock();

    return ec;
}

// IMPORTANT: only by ISR
ECode Thread::ReadyToWakeUpByIsr()
{
    ECode ec;

    assert(IsSleeping());
    assert(NULL == m_pWaitingSyncObject);

    m_pEffectiveScheduleClass->OnThreadWakeUp(this);

    uint32_t uFlags = SaveFlagsAndCli();

    m_uState &= ~ThreadState_InterruptibleSleeping;

    if (IsRunning()) {
        m_pEffectiveScheduleClass->EnterRunningList(this,
            RunningReason_WakeUp);
        ec = NOERROR;
    }
    else {
        ec = S_FALSE;
    }

    RestoreIF(uFlags);

    return ec;
}

void Thread::WakeUpOnTimeout()
{
    bool_t bOriginalPreemption = DzDisablePreemption();

    uint32_t uFlags = SaveFlagsAndCli();

    if (!IsSleeping()) {
        RestoreIF(uFlags);
        DzRestorePreemption(bOriginalPreemption);
        return;
    }

    m_pBindingTimer = NULL;

    if (NULL != m_pWaitingSyncObject) {
        m_pWaitingSyncObject->DetachWaiter(this);
    }

    RestoreIF(uFlags);

    m_pEffectiveScheduleClass->OnThreadWakeUp(this);

    uFlags = SaveFlagsAndCli();

    m_uState &= ~ThreadState_InterruptibleSleeping;

    register bool_t bRunning = IsRunning();

    if (bRunning) {
        m_pEffectiveScheduleClass->EnterRunningList(this,
            RunningReason_WakeUp);
    }

    RestoreIF(uFlags);

    DzRestorePreemption(bOriginalPreemption);

    if (bRunning) NeedReschedule();
}

ECode Thread::Interrupt()
{
    bool_t bOriginalPreemption = DzDisablePreemption();

    if (ThreadState_Finished == m_uPoolThreadState
            || IsFinishingOrFinished()) {
        DzRestorePreemption(bOriginalPreemption);
        return E_THREAD_ALREADY_FINISHED;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    if (!IsInterruptibleSleeping()) {
        m_bPendingInterrupt = TRUE;
        RestoreIF(uFlags);
        DzRestorePreemption(bOriginalPreemption);
        return NOERROR;
    }

    CancelBindingTimer();

    if (NULL != m_pWaitingSyncObject) {
        m_pWaitingSyncObject->DetachWaiter(this);
    }

    m_bInterrupted = TRUE;

    RestoreIF(uFlags);

    m_pEffectiveScheduleClass->OnThreadWakeUp(this);

    m_uState &= ~ThreadState_InterruptibleSleeping;

    register bool_t bRunning = IsRunning();

    if (bRunning) {
        uint32_t uFlags = SaveFlagsAndCli();
        m_pEffectiveScheduleClass->EnterRunningList(
            this, RunningReason_WakeUp);
        RestoreIF(uFlags);
    }

    DzRestorePreemption(bOriginalPreemption);

    if (bRunning) Schedule();

    return NOERROR;
}

ECode Thread::Suspend()
{
    assert(GetCurrentThread() != &g_thread0);

    m_activeLock._Lock();

    m_lock.Lock();

    if (ThreadState_Finished == m_uPoolThreadState
           || IsFinishingOrFinished()) {
        m_lock.Unlock();
        m_activeLock._Unlock();
        return E_THREAD_ALREADY_FINISHED;
    }

    if (0 < m_uNestedSuspend++) {
        assert(IsSuspended());
        m_lock.Unlock();
        m_activeLock._Unlock();
        return NOERROR;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    if (IsRunning()) m_pEffectiveScheduleClass->LeaveRunningList(this);

    m_uState |= ThreadState_Suspended;

    RestoreIF(uFlags);

    m_lock.Unlock();

    m_activeLock._Unlock();

    if (GetCurrentThread() == this) Schedule();

    return NOERROR;
}

ECode Thread::Resume()
{
    m_lock.Lock();

    if (!IsSuspended()) {
        m_lock.Unlock();
        return E_INVALID_OPERATION;
    }

    if (0 < --m_uNestedSuspend) {
        m_lock.Unlock();
        return NOERROR;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    m_uState &= ~ThreadState_Suspended;

    register bool_t bRunning = IsRunning();

    if (bRunning) {
        m_pEffectiveScheduleClass->EnterRunningList(
            this, RunningReason_Resume);
    }

    RestoreIF(uFlags);

    m_lock.Unlock();

    if (bRunning) Schedule();

    return NOERROR;
}

// PROBLEM: It may be reentrant.
void Thread::UndoAll()
{
    m_lock.Lock();
    while (!m_undoOperationListHead.IsEmpty()) {
        UndoOperation *pUndoOperation =
            (UndoOperation *)m_undoOperationListHead.First();
        pUndoOperation->Detach();
        pUndoOperation->m_pNext = NULL;
        m_lock.Unlock();

        pUndoOperation->Undo(this);

        m_lock.Lock();
    }
    m_lock.Unlock();

    m_lock.Lock();
    for (uint_t i = 0; i < MAX_NUMBER_OF_RUOS; i++) {
        if (NULL != m_readerUndoOperations[i].m_pRWLock
            && NULL != m_readerUndoOperations[i].m_pThread) {
            m_readerUndoOperations[i].Detach();
            m_readerUndoOperations[i].m_pThread = NULL;
            m_lock.Unlock();

            m_readerUndoOperations[i].Undo(this);

            m_lock.Lock();
        }
    }
    m_lock.Unlock();
}
#ifdef DEBUG_KMUTEX
STATIC KMutex s_abortLock(__FILE__, __LINE__);
#else
STATIC KMutex s_abortLock;
#endif //DEBUG_KMUTEX

ECode Thread::Abort(CProcess *pOwner)
{
    assert(&g_thread0 != this);

    register Thread *pCurrentThread = GetCurrentThread();

    if (pCurrentThread == this) {
        ExitThread(pOwner);
        assert0();
    }

    s_abortLock.Lock();

    if (InterlockedExchange(&m_bFinishing, TRUE)) {
        s_abortLock.Unlock();
        return NOERROR;
    }

    m_activeLock._Lock();

    bool_t bOriginalPreemption = DzDisablePreemption();

    if (IsFinished()) {
        DzRestorePreemption(bOriginalPreemption);
        m_activeLock._Unlock();
        s_abortLock.Unlock();
        return NOERROR;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    if (IsSleeping()) {
        CancelBindingTimer();

        if (NULL != m_pWaitingSyncObject) {
            m_pWaitingSyncObject->DetachWaiter(this);
        }
    }

    if (IsRunning()) m_pEffectiveScheduleClass->LeaveRunningList(this);

    m_uState = ThreadState_Finished;

    if (ThreadState_Finished != m_uPoolThreadState) {
        DzGetSystemTime(&m_finishTime);
    }

    RestoreIF(uFlags);

    DzRestorePreemption(bOriginalPreemption);

    if (m_pOwner) {
        UInt32 uStackBase =
            InterlockedExchange((Int32 *)&m_uUserStackBase, 0);
        if (uStackBase) {
            m_pOwner->m_AS.Unmap(uStackBase, USER_STACK_SIZE);
        }

        if (m_pOwner->m_pMainThread == this) m_pOwner->m_pMainThread = NULL;
    }

    UndoAll();

    m_joinEvent.Notify();

    m_activeLock._Unlock();

    if (pOwner && ThreadState_Unstarted != m_uPoolThreadState) {
        m_pOwner = NULL;
        pOwner->Release();
    }

    this->Release();

    s_abortLock.Unlock();

    return NOERROR;
}

ECode Thread::SetPriority(
    /* [in] */ ThreadPriority priority)
{
    if (priority < ThreadPriority_Lowest
            || ThreadPriority_Highest < priority) {
        return E_INVALID_ARGUMENT;
    }

    m_lock.Lock();

    if (ThreadState_Finished == m_uPoolThreadState
            || IsFinishingOrFinished()) {
        m_lock.Unlock();
        return E_THREAD_ALREADY_FINISHED;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    assert(m_pScheduleClass);
    m_pScheduleClass->SetThreadPriority(this, priority, IsRunning());

    RestoreIF(uFlags);

    m_lock.Unlock();

    Schedule();

    return NOERROR;
}

ECode Thread::GetPriority(
    /* [out] */ ThreadPriority * pPriority)
{
    if (NULL == pPriority) return E_INVALID_ARGUMENT;

    m_lock.Lock();

    if (ThreadState_Finished == m_uPoolThreadState
            || IsFinishingOrFinished()) {
        m_lock.Unlock();
        return E_THREAD_ALREADY_FINISHED;
    }

    assert(m_pScheduleClass);
    *pPriority = m_pScheduleClass->GetThreadPriority(this);

    m_lock.Unlock();

    return NOERROR;
}

#define INTERRUPTCONTEXT_MIN_LEN 17
ECode Thread::GetContext(ArrayOf<Int32> *pContextArray)
{
    if (!pContextArray || pContextArray->GetLength() < INTERRUPTCONTEXT_MIN_LEN) {
        return E_INVALID_ARGUMENT;
    }

	kprintf("GetThreadContext\n");
    Byte *pCon = (Byte *)pContextArray->GetPayload();

    if (::GetCurrentThread() == this) {
        return E_INVALID_ARGUMENT;
    }

    bool_t bOriginalPreemption = DzDisablePreemption();

    if (m_bFinishing) {
        DzRestorePreemption(bOriginalPreemption);
        return E_THREAD_ALREADY_FINISHED;
    }

#if defined(_arm)
    memcpy(pCon,(InterruptContext *)m_vaKernelStack - 1,
            sizeof(InterruptContext));
#elif defined(_x86)
	memcpy(pCon, (InterruptContext *)m_vaKernelStack - 1,
            sizeof(InterruptContext));

    // x86 have special debug registers
    DebugContext dbgCtx;
    m_pOwner->GetDebugRegisters(&dbgCtx);
    memcpy((pCon + sizeof(InterruptContext)), &dbgCtx, sizeof(DebugRegisterInfo));
#else
#error Unknown architecture
#endif
    DzRestorePreemption(bOriginalPreemption);
    return NOERROR;
}

ECode Thread::SetContext(const ArrayOf<Int32> &contextArray)
{
	kprintf("SetThreadContext\n");

    if (::GetCurrentThread() == this) {
        return E_INVALID_ARGUMENT;
    }

    bool_t bOriginalPreemption = DzDisablePreemption();

    if (m_bFinishing) {
        DzRestorePreemption(bOriginalPreemption);
        return E_THREAD_ALREADY_FINISHED;
    }

#if defined(_arm)
    InterruptContext *pTargetIContext = (InterruptContext *)m_vaKernelStack - 1;
    InterruptContext *pContext = (InterruptContext *)contextArray.GetPayload();
    pTargetIContext->r0 = pContext->r0;
    pTargetIContext->r1 = pContext->r1;
    pTargetIContext->r2 = pContext->r2;
    pTargetIContext->r3 = pContext->r3;
    pTargetIContext->r4 = pContext->r4;
    pTargetIContext->r5 = pContext->r5;
    pTargetIContext->r6 = pContext->r6;
    pTargetIContext->r7 = pContext->r7;
    pTargetIContext->r8 = pContext->r8;
    pTargetIContext->r9 = pContext->r9;
    pTargetIContext->r10 = pContext->r10;
    pTargetIContext->r11 = pContext->r11;
    pTargetIContext->r12 = pContext->r12;
    pTargetIContext->sp = pContext->sp;
    pTargetIContext->lr = pContext->lr;
    pTargetIContext->pc = pContext->pc;
    pTargetIContext->cpsr =
        (pTargetIContext->cpsr & 0xFF) | (pContext->cpsr & 0xFF000000);
#elif defined(_x86)
    InterruptContext *pTargetIContext = (InterruptContext *)m_vaKernelStack - 1;
    Context *pContext = (Context *) contextArray.GetPayload();
    InterruptContext *pInterContext =
            (InterruptContext *)&pContext->m_Context;
    pTargetIContext->eip = pInterContext->eip;
    pTargetIContext->eflags = pInterContext->eflags;
    pTargetIContext->_esp = pInterContext->_esp;
    pTargetIContext->ebx = pInterContext->ebx;
    pTargetIContext->ecx = pInterContext->ecx;
    pTargetIContext->edx = pInterContext->edx;
    pTargetIContext->esi = pInterContext->esi;
    pTargetIContext->edi = pInterContext->edi;
    pTargetIContext->ebp = pInterContext->ebp;
    pTargetIContext->eax = pInterContext->eax;


    m_pOwner->SetDebugRegisters(
            (DebugContext *)&(pContext->m_DebugRegInfo));
#else
#error Unknown architecture
#endif
    DzRestorePreemption(bOriginalPreemption);
    return NOERROR;
}

ECode Thread::GetUserStackTop(Address *pStackTop)
{
    if (!pStackTop) {
        return E_INVALID_ARGUMENT;
    }

    //which stacktop
    bool_t bOriginalPreemption = DzDisablePreemption();

    if (m_bFinishing) {
        DzRestorePreemption(bOriginalPreemption);
        return E_THREAD_ALREADY_FINISHED;
    }

    *pStackTop = m_uUserStackBase + USER_STACK_SIZE;
    DzRestorePreemption(bOriginalPreemption);

    return NOERROR;
}

INLINE void Thread::InheritPriority(const Thread *pThread)
{
    assert(pThread);

    uint32_t uFlags = SaveFlagsAndCli();

    if (IsRunning()) {
        m_pEffectiveScheduleClass->LeaveRunningList(this);
    }

    m_bInherit                  = TRUE;
    m_uEffectiveSchedulePolicy  = pThread->m_uEffectiveSchedulePolicy;
    m_uEffectiveBasePriority    = pThread->m_uEffectiveBasePriority;
    m_uEffectiveDynamicPriority = pThread->m_uEffectiveDynamicPriority;
    m_nEffectiveTimeQuota       = pThread->m_nEffectiveTimeQuota;
    m_pEffectiveScheduleClass   = pThread->m_pEffectiveScheduleClass;

    if (IsRunning()) {
        m_pEffectiveScheduleClass->EnterRunningList(
            this, RunningReason_Other);
    }

    RestoreIF(uFlags);
}

INLINE void Thread::RestorePriority()
{
    uint32_t uFlags = SaveFlagsAndCli();

    if (IsRunning()) {
        m_pEffectiveScheduleClass->LeaveRunningList(this);
    }

    m_bInherit                  = FALSE;
    m_uEffectiveSchedulePolicy  = m_uSchedulePolicy;
    m_uEffectiveBasePriority    = m_uBasePriority;
    m_uEffectiveDynamicPriority = m_uDynamicPriority;
    m_nEffectiveTimeQuota       = m_nTimeQuota;
    m_pEffectiveScheduleClass   = m_pScheduleClass;

    if (IsRunning()) {
        m_pEffectiveScheduleClass->EnterRunningList(
            this, RunningReason_Other);
    }

    RestoreIF(uFlags);
}

// IMPORTANT: when own the m_lock
void Thread::WillToInheritPriority(const Thread *pThread)
{
    assert(pThread);

    if (PriorityGreaterThan(pThread, this)) {
        InheritPriority(pThread);

        uint32_t uFlags = SaveFlagsAndCli();
        if (NULL == m_pWaitingSyncObject
            || NULL == m_pWaitingSyncObject->m_pOwner) {
            RestoreIF(uFlags);
            return;
        }
        RestoreIF(uFlags);

        m_pWaitingSyncObject->m_waitListLock.Lock();
        m_pWaitingSyncObject->WillToInheritPriority(pThread);
        m_pWaitingSyncObject->m_waitListLock.Unlock();
    }
}

void Thread::WaiveInheritedPriority(register bool_t bSchedule)
{
    assert(this == GetCurrentThread());

    m_lock.Lock();

    if (!m_bInherit) {
        m_lock.Unlock();
        return;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    Thread *pPriorityHighestWaiter = NULL;

    register SyncObject *pOwnedSyncObject;
    ForEachDLinkNode(SyncObject *, pOwnedSyncObject,
        &m_ownedSyncObjectListHead) {
        assert(pOwnedSyncObject->m_pOwner == this);
        Thread *pWaiter2 = pOwnedSyncObject->GetPriorityHighestWaiter();
        if (NULL != pWaiter2) {
            if (NULL == pPriorityHighestWaiter
                || PriorityGreaterThan(
                    pWaiter2->m_pEffectiveScheduleClass,
                    pWaiter2->m_uEffectiveDynamicPriority,
                    pPriorityHighestWaiter->m_pEffectiveScheduleClass,
                    pPriorityHighestWaiter->m_uEffectiveDynamicPriority)) {
                pPriorityHighestWaiter = pWaiter2;
            }
        }
    }

    if (NULL != pPriorityHighestWaiter
        && PriorityGreaterThan(
                pPriorityHighestWaiter->m_pEffectiveScheduleClass,
                pPriorityHighestWaiter->m_uEffectiveDynamicPriority,
                m_pScheduleClass, m_uDynamicPriority)) {
        InheritPriority(pPriorityHighestWaiter);

        RestoreIF(uFlags);
    }
    else {
        RestoreIF(uFlags);

        RestorePriority();
    }

    m_lock.Unlock();

    if (bSchedule) Schedule();
}

//
// Global function definitions
//
EXTERN Thread *GetThread0()
{
    return &g_thread0;
}

EXTERN DECL_CODEINIT bool_t CDECL InitThread0()
{
#ifdef _EVC
    g_thread0Stack = (byte_t *)((uint32_t)(g_thread0Original
                    + THREAD0_STACK_SIZE * 2)
                    & (~(THREAD0_STACK_SIZE * 2 - 1)));

#endif
    g_thread0.Initialize0(&g_thread0Stack[THREAD0_STACK_SIZE]);

    return TRUE;
}

STATIC Int32 ReclaimRoutine(void *pvParameter)
{
    Thread::ReclaimFreeThreads();

    return 0;
}

EXTERN DECL_CODEINIT bool_t CDECL InitThreads()
{
    Thread::s_freeListHead.Initialize();

    AddPeriodicTask(1, &ReclaimRoutine, NULL);

    return TRUE;
}

STATIC void CDECL SystemThreadEntry(
    threadroutine_t threadroutine, void *pvParameter)
{
    register Thread *pCurrentThread = GetCurrentThread();
    DzGetSystemTime(&pCurrentThread->m_startTime);
    pCurrentThread->m_uPoolThreadState = ThreadState_Running;

//#ifndef _RELEASE
//    kprintf("System thread: routine: %x, parameter: %x\n",
//            threadroutine, pvParameter);
//#endif // _RELEASE

    assert(threadroutine && *threadroutine);
    pCurrentThread->m_exitCode = (*threadroutine)(pvParameter);

    DzGetSystemTime(&pCurrentThread->m_finishTime);
    pCurrentThread->m_uPoolThreadState = ThreadState_Finished;
    ExitThread(NULL);
    assert(0);
}

EXTERN Thread *CreateSystemThread(
    threadroutine_t threadroutine, void *pvParameter,
    ScheduleClass *pScheduleClass, uint_t uSchedulePolicy)
{
    Thread *pThread = new Thread();
    if (NULL == pThread) return NULL;

    pThread->AddRef();
    pThread->AddRef();
    ECode ec = pThread->Initialize(
        &SystemThreadEntry, threadroutine, pvParameter,
        pScheduleClass, uSchedulePolicy);
    if (FAILED(ec)) {
        pThread->Release();
        pThread->Release();
        return NULL;
    }

    Schedule();

    assert(DzIsSystemThread(pThread));
    return pThread;
}

EXTERN Thread *CreateThread(
    CProcess *pOwner, threadroutine_t threadroutine, void *pvParameter,
    ScheduleClass *pScheduleClass, uint_t uSchedulePolicy)
{
    Thread *pThread = new Thread();
    if (NULL == pThread) return NULL;

    pThread->AddRef();
    ECode ec = pThread->Initialize(
        pOwner, threadroutine, pvParameter,
        pScheduleClass, uSchedulePolicy);
    if (FAILED(ec)) {
        pThread->Release();
        return NULL;
    }

    Schedule();

    return pThread;
}

EXTERN ECode DzCreateKernelThread(
    threadroutine_t threadroutine, PVoid pvArg, UInt32 flags,
    ThreadPriorityRank priorityRank, IThread **ppThread)
{
    switch (priorityRank) {
        case ThreadPriorityRank_Normal:
        case ThreadPriorityRank_SoftRealTime:
            break;
        case ThreadPriorityRank_HardRealTime:
            return E_NOT_IMPLEMENTED;
        default:
            return E_INVALID_ARGUMENT;
    }

    ECode ec;
    uint_t uStackTop;
    IThread *pThread;

    ScheduleClass *pScheduleClass;
    uint_t uSchedulePolicy;
    GetScheduleClass(priorityRank, &pScheduleClass, &uSchedulePolicy);

    if (flags & CreateThreadFlag_System) {
        pThread = CreateSystemThread(
            threadroutine, pvArg, pScheduleClass, uSchedulePolicy);
        if (NULL == pThread) return E_OUT_OF_MEMORY;
    }
    else {
        assert(GetCurrentProcess());

        ec = GetCurrentProcess()->m_threadPool.CreateKernelThread(
                threadroutine, pvArg, flags,
                pScheduleClass, uSchedulePolicy, &pThread);
        if (FAILED(ec)) return ec;

        assert(0 != ((Thread *)pThread)->m_uUserStackBase);

        uStackTop = ((Thread *)pThread)->m_uUserStackBase \
                + USER_STACK_SIZE - USER_STACK_PRESERVED_SIZE;

        memset((void *)(uStackTop + USER_STACK_PRESERVED_SIZE - TLS_SIZE),
                0, TLS_SIZE);

        pThread->Start();
    }

    if (NULL != ppThread) {
        *ppThread = pThread;
    }
    else {
        pThread->Release();
    }

    return NOERROR;
}

EXTERN void UninterruptibleSleep()
{
    register Thread *pCurrentThread = GetCurrentThread();

    pCurrentThread->m_lock.Lock();
    ReadyToUninterruptibleSleepOn();
    pCurrentThread->m_lock.Unlock();

    Schedule();

    assert0();
}

EXTERN void UninterruptibleSleep(uint_t uTicks)
{
    if (0 == uTicks) {
        Schedule();
        return;
    }

    register Thread *pCurrentThread = GetCurrentThread();

    DzTimer timer(uTicks, ScheduleTimeout, pCurrentThread);

    pCurrentThread->m_lock.Lock();
    ReadyToUninterruptibleSleepOn(NULL, &timer);
    timer.Start();
    pCurrentThread->m_lock.Unlock();

    Schedule();

    assert(timer.Due());
}

EXTERN void DzSleep()
{
    register Thread *pCurrentThread = GetCurrentThread();

    pCurrentThread->m_lock.Lock();
    WaitResult wr;
    ReadyToSleepOn(NULL, NULL, &wr);
    if (WaitResult_OK != wr) {
        pCurrentThread->m_lock.Unlock();
        return;
    }
    pCurrentThread->m_lock.Unlock();

    Schedule();

    verify(ClearInterrupted());
}

EXTERN void DzSleep(uint_t uTicks, WaitResult *pResult)
{
    WaitResult wr;
    if (NULL == pResult) pResult = &wr;

    if (0 == uTicks) {
        Schedule();
        *pResult = WaitResult_TimedOut;
        return;
    }

    register Thread *pCurrentThread = GetCurrentThread();

    DzTimer timer(uTicks, ScheduleTimeout, pCurrentThread);

    pCurrentThread->m_lock.Lock();
    ReadyToSleepOn(NULL, &timer, pResult);
    if (WaitResult_OK != *pResult) {
        pCurrentThread->m_lock.Unlock();
        return;
    }
    timer.Start();
    pCurrentThread->m_lock.Unlock();

    Schedule();

    if (ClearInterrupted()) {
        *pResult = WaitResult_Interrupted;
        return;
    }

    assert(timer.Due());
    *pResult = WaitResult_TimedOut;
}

// IMPORTANT:
//  (1) When own current thread's m_lock
//  (2) When own the SyncObject's m_waitListLock if
//  pWaitingSyncObject != NULL
//  or when disable interrupt
EXTERN void ReadyToUninterruptibleSleepOn(
    SyncObject *pWaitingSyncObject, DzTimer *pBindingTimer)
{
    register Thread *pCurrentThread = GetCurrentThread();

    assert(pCurrentThread->IsRunning());
    assert(NULL == pCurrentThread->m_pBindingTimer);
    assert(NULL == pCurrentThread->m_pWaitingSyncObject);

    uint32_t uFlags = SaveFlagsAndCli();

    pCurrentThread->m_pEffectiveScheduleClass->OnThreadSleep(pCurrentThread);

    pCurrentThread->m_pEffectiveScheduleClass->LeaveRunningList(
        pCurrentThread);

    pCurrentThread->m_uState = ThreadState_Sleeping;

    RestoreIF(uFlags);

    pCurrentThread->m_pWaitingSyncObject = pWaitingSyncObject;
    pCurrentThread->m_pBindingTimer = pBindingTimer;
}

// IMPORTANT:
//  (1) When own current thread's m_lock
//  (2) When own the SyncObject's m_waitListLock if
//  pWaitingSyncObject != NULL
//  or when disable interrupt
EXTERN void ReadyToSleepOn(
    SyncObject *pWaitingSyncObject, DzTimer *pBindingTimer,
    WaitResult *pResult)
{
    assert(pResult);

    register Thread *pCurrentThread = GetCurrentThread();

    assert(pCurrentThread->IsRunning());
    assert(NULL == pCurrentThread->m_pBindingTimer);
    assert(NULL == pCurrentThread->m_pWaitingSyncObject);

    if (ClearPendingInterrupt()) {
        *pResult = WaitResult_Interrupted;
        return;
    }

    uint32_t uFlags = SaveFlagsAndCli();

    pCurrentThread->m_pEffectiveScheduleClass->OnThreadSleep(pCurrentThread);

    pCurrentThread->m_pEffectiveScheduleClass->LeaveRunningList(
        pCurrentThread);

    pCurrentThread->m_uState = ThreadState_InterruptibleSleeping;

    RestoreIF(uFlags);

    pCurrentThread->m_pWaitingSyncObject = pWaitingSyncObject;
    pCurrentThread->m_pBindingTimer = pBindingTimer;

    *pResult = WaitResult_OK;
}

EXTERN void DzYield()
{
    register Thread *pCurrentThread = GetCurrentThread();

    pCurrentThread->m_lock.Lock();

    assert(pCurrentThread->IsRunning());
    assert(NULL == pCurrentThread->m_pBindingTimer);
    assert(NULL == pCurrentThread->m_pWaitingSyncObject);

    uint32_t uFlags = SaveFlagsAndCli();

    pCurrentThread->m_pEffectiveScheduleClass->OnThreadYield(pCurrentThread);

    RestoreIF(uFlags);

    pCurrentThread->m_lock.Unlock();

    Schedule();
}

EXTERN void ExitThread(CProcess *pOwner)
{
    register Thread *pCurrentThread = GetCurrentThread();
    assert(&g_thread0 != pCurrentThread);

    if (InterlockedExchange(&pCurrentThread->m_bFinishing, TRUE)) {
        UninterruptibleSleep();
        assert0();
    }

    if (pCurrentThread->m_pOwner) {
        UInt32 uStackBase = InterlockedExchange(
            (Int32 *)&pCurrentThread->m_uUserStackBase, 0);
        if (uStackBase) {
            pCurrentThread->m_pOwner->m_AS.Unmap(uStackBase, USER_STACK_SIZE);
        }

        if (pCurrentThread->m_pOwner->m_pMainThread == pCurrentThread) {
            pCurrentThread->m_pOwner->m_pMainThread = NULL;
        }
    }

    pCurrentThread->UndoAll();

    pCurrentThread->m_joinEvent.Notify();

    if (pOwner &&
            ThreadState_Unstarted != pCurrentThread->m_uPoolThreadState) {
        pCurrentThread->m_pOwner = NULL;
        pOwner->Release();
    }

    bool_t bOriginalPreemption = DzDisablePreemption();

    assert(pCurrentThread->IsRunning());
    assert(NULL == pCurrentThread->m_pBindingTimer);
    assert(NULL == pCurrentThread->m_pWaitingSyncObject);

    uint32_t uFlags = SaveFlagsAndCli();

    pCurrentThread->m_pEffectiveScheduleClass->LeaveRunningList(
        pCurrentThread);

    pCurrentThread->m_uState = ThreadState_Finished;

    if (ThreadState_Finished != pCurrentThread->m_uPoolThreadState) {
        DzGetSystemTime(&pCurrentThread->m_finishTime);
    }

    RestoreIF(uFlags);

    pCurrentThread->Release();

    DzRestorePreemption(bOriginalPreemption);

    ScheduleNoReturn();
}

ECode DzGetCurrentThread(IThread **ppCurrentThread)
{
    assert(ppCurrentThread);

    register Thread *pCurrentThread = GetCurrentThread();
    *ppCurrentThread = pCurrentThread;
    pCurrentThread->AddRef();
    return NOERROR;
}

EXTERN bool_t DzIsSystemThread(IThread *pThread)
{
    assert(pThread);

    return (NULL == ((Thread *)pThread)->m_pOwner);
}

STATIC uint8_t s_tfFlags = 0;

EXTERN bool_t DzAcquireThreadFieldSlot(uint_t *puFieldIndex)
{
    assert(puFieldIndex);

    uint32_t uFlags = SaveFlagsAndCli();
    for (uint_t uIndex = 0; uIndex < TF_MINIMUM_AVAILABLE; uIndex++) {
        if (0 == TestBit(uIndex, &s_tfFlags)) {
            SetBit(uIndex, &s_tfFlags);
            RestoreIF(uFlags);

            *puFieldIndex = uIndex;
            return TRUE;
        }
    }
    RestoreIF(uFlags);

    return FALSE;
}

//EXTERN void DzRelinquishThreadFieldSlot(uint_t uFieldIndex)
//{
//    assert(TF_MINIMUM_AVAILABLE > uFieldIndex);
//    assert(0 != TestBit(uFieldIndex, &s_tfFlags));
//
//    uint32_t uFlags = SaveFlagsAndCli();
//    ClearBit(uFieldIndex, s_tfFlags);
//    RestoreIF(uFlags);
//}

EXTERN void **DzGetThreadFieldAddress(uint_t uFieldIndex)
{
    assert(TF_MINIMUM_AVAILABLE > uFieldIndex);
    assert(0 != TestBit(uFieldIndex, &s_tfFlags));

    return &(GetCurrentThread()->m_pvFields[uFieldIndex]);
}

EXTERN void UpdateCurrentThreadTime(uint_t uTicks, bool_t bUserMode)
{
    register Thread *pCurrentThread = GetCurrentThread();

    uint32_t uFlags = SaveFlagsAndCli();

    if (bUserMode) {
        pCurrentThread->m_uUserProcessorTicks += uTicks;
        if (NULL != pCurrentThread->m_pOwner) {
            pCurrentThread->m_pOwner->m_uUserProcessorTicks += uTicks;
        }
    }
    else {
        pCurrentThread->m_uPrivilegedProcessorTicks += uTicks;
        if (NULL != pCurrentThread->m_pOwner) {
            pCurrentThread->m_pOwner->m_uPrivilegedProcessorTicks += uTicks;
        }
    }

    pCurrentThread->m_pEffectiveScheduleClass->UpdateTime(uTicks);

    if (pCurrentThread->IsRunning()) {
        bool_t bNeedReschedule =
            pCurrentThread->m_pEffectiveScheduleClass->UpdateThreadTime(
                pCurrentThread, uTicks);

        if (bNeedReschedule) pCurrentThread->m_bNeedReschedule = TRUE;
    }

    RestoreIF(uFlags);
}

//
// Periodic Tasks
//
class PeriodicTask : public DLinkNode
{
public:
    int             m_nOriginalTime;    // time in second
    int             m_nLeftTime;
    threadroutine_t m_fnTaskRoutine;
    void            *m_pvRoutineArg;

public:
    PeriodicTask(int nTime, threadroutine_t fnTaskRoutine, void *pvArg)
    {
        m_nOriginalTime = m_nLeftTime = nTime;
        m_fnTaskRoutine = fnTaskRoutine;
        m_pvRoutineArg = pvArg;
    }
};

STATIC DLinkNode s_taskLink;
#ifdef DEBUG_KMUTEX
STATIC KMutex s_taskLinkLock(__FILE__, __LINE__);
#else
STATIC KMutex s_taskLinkLock;
#endif //DEBUG_KMUTEX
STATIC bool_t s_bContinue = TRUE;
STATIC Thread *s_pTaskThread = NULL;

EXTERN PVoid STDCALL AddPeriodicTask(
    int nTime, threadroutine_t fnTaskRoutine, void *pvArg)
{
    PeriodicTask *pTask;

    pTask = new PeriodicTask(nTime, fnTaskRoutine, pvArg);
    if (!pTask) return NULL;

    s_taskLinkLock.Lock();
    s_taskLink.InsertPrev(pTask);
    s_taskLinkLock.Unlock();

    return (PVoid)pTask;
}

EXTERN void STDCALL CancelPeriodicTask(PVoid taskHandle)
{
    s_taskLinkLock.Lock();
    ((PeriodicTask *)taskHandle)->Detach();
    s_taskLinkLock.Unlock();

    delete (PeriodicTask *)taskHandle;
}

STATIC Int32 HandlePeriodicTasks(void *pvParameter)
{
    PeriodicTask *pTask;

    while (s_bContinue) {
        DzSleep(DzMillisecondsToTicks(1000), NULL);

        s_taskLinkLock.Lock();
        ForEachDLinkNode(PeriodicTask *, pTask, &s_taskLink) {
            pTask->m_nLeftTime--;
            if (0 == pTask->m_nLeftTime) {
                (*pTask->m_fnTaskRoutine)(pTask->m_pvRoutineArg);
                pTask->m_nLeftTime = pTask->m_nOriginalTime;
            }
        }
        s_taskLinkLock.Unlock();
    }

    return 0;
}

EXTERN DECL_CODEINIT bool_t InitPeriodicTasks()
{
    s_taskLink.Initialize();
    return TRUE;
}

EXTERN DECL_CODEINIT bool_t StartPeriodicTasks()
{
    s_pTaskThread = CreateSystemThread(
            &HandlePeriodicTasks, NULL,
            g_pDefaultScheduleClass, g_uDefaultSchedulePolicy);
    if (NULL == s_pTaskThread) {
        assert(0 && "Create periodic thread failed.");
        return FALSE;
    }

    s_pTaskThread->SetPriority(ThreadPriority_Highest);
    return TRUE;
}

EXTERN void StopPeriodicTasks()
{
    if (NULL != s_pTaskThread) {
        s_bContinue = FALSE;
        s_pTaskThread->m_joinEvent.UninterruptibleWait(NULL);
    }
}
